package com.lagou.rpc.consumer.client;

import com.lagou.rpc.consumer.handler.RpcClientHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 客户端
 * 1.连接Netty服务端
 * 2.提供给调用者主动关闭资源的方法
 * 3.提供消息发送的方法
 */
@Component
public class RpcClient {

    private NioEventLoopGroup group;
    private Channel channel ;

    private String ip;
    private int port;

    private RpcClientHandler rpcClientHandler = new RpcClientHandler();

    private ExecutorService executors = Executors.newCachedThreadPool();

    public RpcClient() {
    }

    public RpcClient(String ip, int port) {
        this.ip = ip;
        this.port = port;
        initClient();
    }


    /**
     * 初始化Bootstrap
     */
    public final Bootstrap getBootstrap() {
        if (null == group) {
            group = new NioEventLoopGroup();
        }
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,3000)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new StringEncoder());//String类型编码器
                        pipeline.addLast(new StringDecoder());//String类型解码器
                        //业务处理类
                        pipeline.addLast(rpcClientHandler);
                    }
                });
        return bootstrap;
    }


    /**
     * 1.连接Netty服务端
     */
    public void initClient(){
        try {
            group = new NioEventLoopGroup();
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE,Boolean.TRUE)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,3000)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new StringEncoder());//String类型编码器
                            pipeline.addLast(new StringDecoder());//String类型解码器
                            //业务处理类
                            pipeline.addLast(rpcClientHandler);
                        }
                    });

            //连接netty服务器
            channel = bootstrap.connect(ip, port).sync().channel();
           // ChannelFuture future = bootstrap.connect(ip, port).sync();
            System.out.println("客户端启动成功！");
        } catch (InterruptedException e) {
            e.printStackTrace();
            if (channel!=null){
                channel.close();
            }
            if (group!=null){
                group.shutdownGracefully();
            }
        }
    }

    //提供给调用者主动关闭资源的方法
    public void close(){
        if (channel!=null){
            channel.close();
        }
        if (group!=null){
            group.shutdownGracefully();
        }
    }

    //连接客户端
    public  final Channel connectServer(String ip,int port,Bootstrap bootstrap)  {
        try {
            Map<String , ChannelFuture> result = new HashMap<>();
            //连接netty服务器
            channel = bootstrap.connect(ip, port).sync().channel();
            System.out.println("客户端连接服务器【"+ip+":"+port+"】成功！");
            return channel;
        }catch (Exception e){
            e.printStackTrace();
            if (channel!=null){
                channel.close();
            }
            if (group!=null){
                group.shutdownGracefully();
            }
        }
        return null;
    }

    //关闭channel
    public void closeChannel(Channel channel){
        if (channel!=null){
            channel.close();
        }
    }

    //提供消息发送的方法
    public Object send(String msg) throws ExecutionException, InterruptedException {
        rpcClientHandler.setSendMsg(msg);//设置需要发送给服务端的消息
        Future future = executors.submit(rpcClientHandler);//此处线程池执行后，
                                                            // rpcClientHandler中的call方法分配到时间片后就会执行
        return future.get();//服务端返回的消息--此处get的结果其实就是call方法的返回值
    }


}
